package com.intramirror.product.controller;

import com.intramirror.core.common.exception.ValidateException;
import com.intramirror.core.common.response.ErrorResponse;
import com.intramirror.core.common.response.Response;
import com.intramirror.core.net.http.OkHttpUtils;
import com.intramirror.product.constant.AlgorithmValidationConstant;
import com.intramirror.product.controller.price.ProductDiscountByJobController;
import com.intramirror.product.entity.ImPriceAlgorithm;
import com.intramirror.product.entity.ImPriceAlgorithmRule;
import com.intramirror.product.entity.ImPriceAlgorithmRuleBrand;
import com.intramirror.product.entity.ImPriceDiscountMapping;
import com.intramirror.product.mapper.AlgorithmOperationMapper;
import com.intramirror.product.mapper.ImPriceAlgorithmMapper;
import com.intramirror.product.mapper.ImPriceAlgorithmRuleBrandMapper;
import com.intramirror.product.mapper.ImPriceAlgorithmRuleMapper;
import com.intramirror.product.mapper.ImPriceDiscountMappingMapper;
import com.intramirror.product.service.IPriceRuleService;
import com.intramirror.product.utils.ConvertUtil;
import com.intramirror.utils.transform.JsonTransformUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/algorithm/operation")
public class AlgorithmOperationController {

    private static final Logger logger = LoggerFactory.getLogger(AlgorithmOperationController.class);

    @Autowired
    private AlgorithmOperationMapper algorithmOperationMapper;

    @Autowired
    private ImPriceAlgorithmMapper imPriceAlgorithmMapper;

    @Autowired
    private ImPriceAlgorithmRuleMapper imPriceAlgorithmRuleMapper;

    @Autowired
    private ImPriceAlgorithmRuleBrandMapper imPriceAlgorithmRuleBrandMapper;

    @Autowired
    private ImPriceDiscountMappingMapper imPriceDiscountMappingMapper;

    @Autowired
    private IPriceRuleService iPriceRuleService;

    @Autowired
    private ProductDiscountByJobController productDiscountByJobController;

    @GetMapping("/product")
    public Response product() {
        List<Long> product = algorithmOperationMapper.selectProduct();
        for (int i = 0; i < product.size(); i++) {
            Long productId = product.get(i);
            Response response = productDiscountByJobController.updateProductDiscountById(productId);
            logger.info("AlgorithmOperationController.product,i:{}",i);
            logger.info("AlgorithmOperationController.product,product_id:{}",productId);
            logger.info("AlgorithmOperationController.product,response:{}",response);
        }
        return Response.success();
    }

    @GetMapping("/product2")
    public Response product2() {
        List<Long> product = algorithmOperationMapper.selectProduct2();
        for (int i = 0; i < product.size(); i++) {
            try {
                Long productId = product.get(i);
                Response response = productDiscountByJobController.updateProductDiscountById(productId);
                logger.info("AlgorithmOperationController.sku,i:{}",i);
                logger.info("AlgorithmOperationController.sku,product_id:{}",productId);
                logger.info("AlgorithmOperationController.sku,response:{}",response);
            } catch (Exception e){
                logger.error("product2,error:{}",e);
            }
        }
        return Response.success();
    }

    @GetMapping("/carryOver")
    public Response handleCarryOver() {
        List<Long> product = algorithmOperationMapper.selectCarryOver();
        for (int i = 0; i < product.size(); i++) {
            try {
                Long productId = product.get(i);
                Response response = productDiscountByJobController.updateProductDiscountById(productId);
                logger.info("AlgorithmOperationController.handleCarryOver,i:{}",i);
                logger.info("AlgorithmOperationController.handleCarryOver,product_id:{}",productId);
                logger.info("AlgorithmOperationController.handleCarryOver,response:{}",response);
            } catch (Exception e){
                logger.error("handleCarryOver,error:{}",e);
            }
        }
        return Response.success();
    }

    /**
     * 根据categoryType获取seasons
     *
     * @param categoryType
     *         adult-1 kids-2
     * @return
     */
    @GetMapping("/season/{categoryType}")
    public Response season(@PathVariable("categoryType") Long categoryType) {
        return Response.status(1).data(algorithmOperationMapper.getSeason(categoryType));
    }

    /**
     * 获取所有season
     *
     * @return
     */
    @GetMapping("/season/list")
    public Response season() {
        return Response.status(1).data(algorithmOperationMapper.getAllSeason());
    }

    @GetMapping("/{imPriceAlgorithmId}/{season}/running/count")
    public Response count(@PathVariable("imPriceAlgorithmId") Long imPriceAlgorithmId, @PathVariable("season") String season) {
        return Response.status(1).data(algorithmOperationMapper.getAlgorithmRunningCount(imPriceAlgorithmId, season));
    }

    /**
     * 根据categoryType+season获取算法
     *
     * @param categoryType
     *         adult-1 kids-2
     * @param season
     * @return
     */
    @GetMapping("/list/{categoryType}/{season}")
    public Response algorithm(@PathVariable("categoryType") Long categoryType, @PathVariable("season") String season) {
        return Response.status(1).data(algorithmOperationMapper.getAlgorithm(categoryType, season));
    }

    /**
     * 获取IM Discount明细
     *
     * @param imPriceAlgorithmId
     * @return
     */
    @GetMapping("/info/{imPriceAlgorithmId}")
    public Response algorithmDiscount(@PathVariable("imPriceAlgorithmId") Long imPriceAlgorithmId) {
        List<Map<String, Object>> algorithmBrands = algorithmOperationMapper.getAlgorithmBrand(imPriceAlgorithmId);
        List<Map<String, Object>> algorithmDiscounts = algorithmOperationMapper.getAlgorithmDiscount(imPriceAlgorithmId);
        return Response.status(1).data(this.handleStructure(algorithmBrands, algorithmDiscounts));
    }

    /**
     * 模糊查询品牌接口
     *
     * @param brandName
     * @return
     */
    @GetMapping("/brand")
    public Response brand(String brandName) {
        brandName = brandName == null ? "" : brandName;
        return Response.status(1).data(algorithmOperationMapper.getBrand(brandName));
    }

    /**
     * 删除品牌
     * @param
     * @return
     */
    /*@DeleteMapping("/brand/{imPriceAlgorithmRuleBrandId}")
    public Response deleteImPriceAlgorithmRuleBrand(@PathVariable("imPriceAlgorithmRuleBrandId") Long imPriceAlgorithmRuleBrandId){
        return Response.status(1).data(algorithmOperationMapper.deleteImPriceAlgorithmRuleBrandById(imPriceAlgorithmRuleBrandId));
    }*/

    /**
     * 删除season
     *
     * @param categoryType
     * @param season
     * @return
     */
    @DeleteMapping("/season/{categoryType}/{season}")
    public Response deleteImpriceAlgorithmSeason(@PathVariable("categoryType") Long categoryType, @PathVariable("season") String season)
            throws ValidateException {
        logger.info("deleteImpriceAlgorithmSeason,categoryType:{},season:{}", categoryType, season);
        // check
        int count = algorithmOperationMapper.getPriceChangeRuleCountByCategoryAndSeasonCount(categoryType, season);
        if (count > 0) {
            throw new ValidateException(new ErrorResponse(AlgorithmValidationConstant.used_algorithm_desc));
        }

        algorithmOperationMapper.deleteImpriceAlgorithmSeason(categoryType, season);
        return Response.success();
    }

    /**
     * 删除算法
     *
     * @param imPriceAlgorithmId
     * @return
     */
    @DeleteMapping("/algorithm/{imPriceAlgorithmId}")
    public Response deleteImPriceAlgorithm(@PathVariable("imPriceAlgorithmId") Long imPriceAlgorithmId) throws ValidateException {
        logger.info("deleteImPriceAlgorithm,imPriceAlgorithmId:{}", imPriceAlgorithmId);
        // check
        int count = algorithmOperationMapper.getPriceChangeRuleCountByAlgorithmId(imPriceAlgorithmId);
        if (count > 0) {
            throw new ValidateException(new ErrorResponse(AlgorithmValidationConstant.used_algorithm_desc));
        }

        algorithmOperationMapper.deleteImPriceAlgorithmById(imPriceAlgorithmId);
        algorithmOperationMapper.deleteImPriceAlgorithmRuleByAlgorithmId(imPriceAlgorithmId);
        algorithmOperationMapper.deleteImPriceAlgorithmRuleBrandByAlgorithmId(imPriceAlgorithmId);
        algorithmOperationMapper.deleteImPriceDiscountMappingByAlgorithmId(imPriceAlgorithmId);
        return Response.success();
    }

    /**
     * 删除算法Rule
     *
     * @param imPriceAlgorithmRuleId
     * @return
     */
    @DeleteMapping("/rule/{imPriceAlgorithmRuleId}")
    @Transactional
    public Response deleteImPriceAlgorithmRule(@PathVariable("imPriceAlgorithmRuleId") Long imPriceAlgorithmRuleId) {
        logger.info("deleteImPriceAlgorithmRule,imPriceAlgorithmRuleId:{}", imPriceAlgorithmRuleId);
        algorithmOperationMapper.updateSaveAtByRuleId(imPriceAlgorithmRuleId);
        algorithmOperationMapper.deleteImPriceAlgorithmRuleById(imPriceAlgorithmRuleId);
        algorithmOperationMapper.deleteImPriceAlgorithmRuleBrandByRuleId(imPriceAlgorithmRuleId);
        algorithmOperationMapper.deleteImPriceDiscountMappingByRuleId(imPriceAlgorithmRuleId);
        return Response.success();
    }

    @PostMapping("/algorithm/copy")
    @Transactional
    public Response copy(@RequestBody Map<String, Object> data) throws Exception {
        logger.info("copy,data:{}", JsonTransformUtil.toJson(data));
        this.copyAlgorithm(data);
        return Response.success();
    }

    /**
     * 新增品牌算法
     *
     * @param data
     * @return
     */
    @PostMapping("/add/discount")
    @Transactional
    public Response addImPriceAlgorithmRule(@RequestBody Map<String, Object> data) {
        logger.info("addImPriceAlgorithmRule,data:{}", JsonTransformUtil.toJson(data));
        this.handleAddImAlgorithmRule(data);
        return Response.success();
    }

    /**
     * 增加一个算法
     *
     * @param data
     * @return
     */
    @PostMapping("/add/algorithm")
    @Transactional
    public Response addImPriceAlgorithm(@RequestBody Map<String, Object> data) throws ValidateException {
        logger.info("addImPriceAlgorithm,data:{}", JsonTransformUtil.toJson(data));
        String season = data.get("season").toString();
        String name = data.get("name").toString();
        String categoryType = data.get("categoryType").toString();

        // check
        Long imPriceAlgorithmId = algorithmOperationMapper.getAlgorithmCountByCategoryAndSeasonAndName(Long.parseLong(categoryType), season, name);
        if (imPriceAlgorithmId != null) {
            throw new ValidateException(new ErrorResponse(AlgorithmValidationConstant.exists_duplicate_name_desc));
        }

        this.addAlgorithm(season, name, categoryType);
        return Response.success();
    }

    @PostMapping("/add/season")
    @Transactional
    public Response addSeason(@RequestBody Map<String, Object> data) throws ValidateException {
        logger.info("addSeason,data:{}", JsonTransformUtil.toJson(data));
        String season = data.get("season").toString();
        String categoryType = data.get("categoryType").toString();

        // check
        int count = algorithmOperationMapper.getAlgorithmCountByCategoryAndSeason(Long.parseLong(categoryType), season);
        if (count > 0) {
            throw new ValidateException(new ErrorResponse(AlgorithmValidationConstant.exists_duplicate_name_desc));
        }

        this.addAlgorithm(season, "日常", categoryType);
        this.addAlgorithm(season, "大促", categoryType);
        this.addAlgorithm(season, "小促", categoryType);
        return Response.success();
    }

    @GetMapping("/used/{imPriceAlgorithmId}/{season}")
    public Response getUsedBoutiqueRule(@PathVariable("imPriceAlgorithmId") Long imPriceAlgorithmId, @PathVariable("season") String season) {
        return Response.status(1).data(algorithmOperationMapper.getUsedBoutiqueRule(imPriceAlgorithmId, season));
    }

    /**
     * 在算法中新增品牌
     * @param data
     * @return
     */
    /*@PostMapping("/add/brand")
    public Response addBrandByImPriceAlgorithmRule(@RequestBody Map<String,Object> data) {
        Long imPriceAlgorithmRuleId = Long.valueOf(data.get("imPriceAlgorithmRuleId").toString());
        Long brandId = Long.valueOf(data.get("brandId").toString());

        ImPriceAlgorithmRuleBrand imPriceAlgorithmRuleBrand = new ImPriceAlgorithmRuleBrand();
        imPriceAlgorithmRuleBrand.setImPriceAlgorithmRuleId(imPriceAlgorithmRuleId);
        imPriceAlgorithmRuleBrand.setBrandId(brandId);
        imPriceAlgorithmRuleBrand.setEnabled(true);
        imPriceAlgorithmRuleBrandMapper.insert(imPriceAlgorithmRuleBrand);
        return Response.status(1).data(imPriceAlgorithmRuleBrand);
    }*/

    /**
     * 编辑折扣
     *
     * @return
     */
    @PostMapping("/update/discount")
    @Transactional
    public Response updateImPriceDiscountMapping(@RequestBody Map<String, Object> data) {
        logger.info("updateImPriceDiscountMapping,data:{}", JsonTransformUtil.toJson(data));
        List<Map<String, Object>> discountList = (List<Map<String, Object>>) data.get("discountList");
        List<Map<String, Object>> brandList = (List<Map<String, Object>>) data.get("brandList");
        Long imPriceAlgorithmRuleId = Long.valueOf(data.get("imPriceAlgorithmRuleId").toString());
        algorithmOperationMapper.updateImPriceAlgorithmRuleUpdatedById(imPriceAlgorithmRuleId);

        this.checkEditRule(null, imPriceAlgorithmRuleId, brandList, discountList);

        algorithmOperationMapper.deleteImPriceAlgorithmRuleBrandByRuleId(imPriceAlgorithmRuleId);
        for (Map<String, Object> brand : brandList) {
            Long brandId = Long.valueOf(brand.get("brandId").toString());
            this.addImPriceAlgorithmRuleBrand(brandId, imPriceAlgorithmRuleId);
        }

        algorithmOperationMapper.deleteImPriceDiscountMappingByRuleId(imPriceAlgorithmRuleId);
        for (Map<String, Object> discount : discountList) {
            int imDiscountOff = Integer.parseInt(discount.get("imDiscountOff").toString());
            int boutiqueDiscountOff = Integer.parseInt(discount.get("boutiqueDiscountOff").toString());
            this.addImPriceDiscountMapping(imPriceAlgorithmRuleId, boutiqueDiscountOff, imDiscountOff);
        }
        algorithmOperationMapper.updateSaveAtByRuleId(imPriceAlgorithmRuleId);
        return Response.success();
    }

    /**
     * 处理成前端可用的格式
     *
     * @param algorithmBrands
     * @param algorithmDiscounts
     * @return
     */
    private List<Map<String, Object>> handleStructure(List<Map<String, Object>> algorithmBrands, List<Map<String, Object>> algorithmDiscounts) {
        List<Map<String, Object>> datas = new ArrayList<>();
        for (Map<String, Object> algorithmBrand : algorithmBrands) {
            int imPriceAlgorithmRuleId = Integer.parseInt(algorithmBrand.get("imPriceAlgorithmRuleId").toString());

            boolean flag = false;
            for (Map<String, Object> data : datas) {
                List<Map<String, Object>> brandList = (List<Map<String, Object>>) data.get("brandList");

                for (Map<String, Object> brand : brandList) {
                    if (imPriceAlgorithmRuleId == Integer.parseInt(brand.get("imPriceAlgorithmRuleId").toString())) {
                        flag = true;
                        break;
                    }
                }
                if (flag) {
                    brandList.add(algorithmBrand);
                }
            }

            if (!flag) {
                Map<String, Object> algorithm = new HashMap<>();
                List<Map<String, Object>> brandList = new ArrayList<>();
                brandList.add(algorithmBrand);
                algorithm.put("brandList", brandList);

                List<Map<String, Object>> discountList = new ArrayList<>();
                for (Map<String, Object> algorithmDiscount : algorithmDiscounts) {
                    if (imPriceAlgorithmRuleId == Integer.parseInt(algorithmDiscount.get("imPriceAlgorithmRuleId").toString())) {

                        discountList.add(algorithmDiscount);
                    }
                }

                algorithm.put("discountList", discountList);
                algorithm.put("imPriceAlgorithmRuleId", algorithmBrand.get("imPriceAlgorithmRuleId"));
                if (ConvertUtil.toInteger(algorithmBrand.get("algorithmRuleType")) == 1) {
                    datas.add(0, algorithm);
                } else {
                    datas.add(algorithm);
                }
            }

        }
        return datas;
    }

    /**
     * 新增ImAlgorithmRule
     *
     * @param data
     */
    public void handleAddImAlgorithmRule(Map<String, Object> data) {
        List<Map<String, Object>> discountList = (List<Map<String, Object>>) data.get("discountList");
        List<Map<String, Object>> brandList = (List<Map<String, Object>>) data.get("brandList");
        Long imPriceAlgorithmId = Long.valueOf(data.get("imPriceAlgorithmId").toString());
        this.checkEditRule(imPriceAlgorithmId, null, brandList, discountList);

        Long imPriceAlgorithmRuleId = this.addImPriceAlgorithmRule(imPriceAlgorithmId, "2");
        for (Map<String, Object> brand : brandList) {
            Long brandId = Long.valueOf(brand.get("brandId").toString());
            this.addImPriceAlgorithmRuleBrand(brandId, imPriceAlgorithmRuleId);
        }

        for (Map<String, Object> discount : discountList) {
            int boutiqueDiscountOff = Integer.parseInt(discount.get("boutiqueDiscountOff").toString());
            int imDiscountOff = Integer.valueOf(discount.get("imDiscountOff").toString());
            this.addImPriceDiscountMapping(imPriceAlgorithmRuleId, boutiqueDiscountOff, imDiscountOff);
        }
        algorithmOperationMapper.updateSaveAtById(imPriceAlgorithmId);
    }

    private void checkEditRule(Long imPriceAlgorithmId, Long imPriceAlgorithmRuleId, List<Map<String, Object>> brandList,
            List<Map<String, Object>> discountList) {
        // check 是否为空
        if (CollectionUtils.isEmpty(brandList)) {
            throw new ValidateException(new ErrorResponse(AlgorithmValidationConstant.missing_brand_desc));
        }
        if (CollectionUtils.isEmpty(discountList)) {
            throw new ValidateException(new ErrorResponse(AlgorithmValidationConstant.missing_discount_desc));
        }

        // check boutique不可重复
        if (!this.ifUniqueDiscountList(discountList)) {
            throw new ValidateException(new ErrorResponse(AlgorithmValidationConstant.exists_duplicate_discount_desc));
        }

        //check 符合规则
        String result = this.ifNormalDiscount(discountList);
        if (StringUtils.isNotBlank(result)) {
            throw new ValidateException(new ErrorResponse(AlgorithmValidationConstant.error_discount_desc + "," + result));
        }

        // check 品牌不可重复
        List<String> brands = new ArrayList<>();
        if (!ifBrandUnique(brands, brandList)) {
            throw new ValidateException(new ErrorResponse(AlgorithmValidationConstant.exists_duplicate_brand_desc));
        }

        // check品牌不与其他rule冲突
        if (imPriceAlgorithmId == null) {
            int count = algorithmOperationMapper.getAlgorithmRuleCountByRuleIdAndBrands(imPriceAlgorithmRuleId, brands);
            if (count > 0) {
                throw new ValidateException(new ErrorResponse(AlgorithmValidationConstant.exists_duplicate_brand_desc));
            }
        } else {
            int count = algorithmOperationMapper.getAlgorithmRuleCountByAlgorithmIdAndBrands(imPriceAlgorithmId, brands);
            if (count > 0) {
                throw new ValidateException(new ErrorResponse(AlgorithmValidationConstant.exists_duplicate_brand_desc));
            }
        }
    }

    public boolean ifBrandUnique(List<String> brands, List<Map<String, Object>> brandList) {
        for (Map<String, Object> brand : brandList) {
            if (brands.contains(brand.get("brandId").toString())) {
                return false;
            }
            brands.add(brand.get("brandId").toString());
        }
        return true;
    }

    public String ifNormalDiscount(List<Map<String, Object>> discountList) {
        for (Map<String, Object> discount : discountList) {
            int boutiqueDiscountOff = Integer.parseInt(discount.get("boutiqueDiscountOff").toString());
            int imDiscountOff = Integer.valueOf(discount.get("imDiscountOff").toString());

            double im = Float.valueOf((1 - imDiscountOff / 100F));
            double boutique = Float.valueOf(((1 - boutiqueDiscountOff / 100F) / 1.22F) * 1.02F);

            if (im < boutique) {
                return "boutiqueDiscountOff:" + boutiqueDiscountOff + ",imDiscountOff:" + imDiscountOff;
            }
        }
        return "";
    }

    public boolean ifUniqueDiscountList(List<Map<String, Object>> discountList) {
        List<String> discounts = new ArrayList<>();
        for (Map<String, Object> discount : discountList) {
            String boutiqueDiscountOff = discount.get("boutiqueDiscountOff").toString();

            if (discounts.contains(boutiqueDiscountOff)) {
                return false;
            }
            discounts.add(boutiqueDiscountOff);
        }
        return true;
    }

    private Long addImPriceAlgorithmRule(Long imPriceAlgorithmId, String type) {
        ImPriceAlgorithmRule imPriceAlgorithmRule = new ImPriceAlgorithmRule();
        imPriceAlgorithmRule.setImPriceAlgorithmId(imPriceAlgorithmId);
        imPriceAlgorithmRule.setAlgorithmRuleType(new Byte(type)); // brand规则
        imPriceAlgorithmRule.setCreatedAt(new Date());
        imPriceAlgorithmRule.setUpdatedAt(new Date());
        imPriceAlgorithmRule.setEnabled(true);
        imPriceAlgorithmRuleMapper.insert(imPriceAlgorithmRule);
        Long imPriceAlgorithmRuleId = imPriceAlgorithmRule.getImPriceAlgorithmRuleId();
        return imPriceAlgorithmRuleId;
    }

    private Long addImPriceAlgorithmRuleBrand(Long brandId, Long imPriceAlgorithmRuleId) {
        ImPriceAlgorithmRuleBrand imPriceAlgorithmRuleBrand = new ImPriceAlgorithmRuleBrand();
        imPriceAlgorithmRuleBrand.setImPriceAlgorithmRuleId(imPriceAlgorithmRuleId);
        imPriceAlgorithmRuleBrand.setBrandId(brandId);
        imPriceAlgorithmRuleBrand.setEnabled(true);
        imPriceAlgorithmRuleBrandMapper.insert(imPriceAlgorithmRuleBrand);
        return imPriceAlgorithmRuleBrand.getImPriceAlgorithmRuleBrandId();
    }

    private void addImPriceDiscountMapping(Long imPriceAlgorithmRuleId, int boutiqueDiscountOff, int imDiscountOff) {
        ImPriceDiscountMapping imPriceDiscountMapping = new ImPriceDiscountMapping();
        imPriceDiscountMapping.setImPriceAlgorithmRuleId(imPriceAlgorithmRuleId);
        imPriceDiscountMapping.setBoutiqueDiscountOff(100 - boutiqueDiscountOff);
        imPriceDiscountMapping.setImDiscountOff(100 - imDiscountOff);
        imPriceDiscountMapping.setCreatedAt(new Date());
        imPriceDiscountMapping.setUpdatedAt(new Date());
        imPriceDiscountMapping.setEnabled(true);
        imPriceDiscountMappingMapper.insert(imPriceDiscountMapping);
    }

    private Long addImPriceAlgorithm(String categoryType, String season, String name) {
        ImPriceAlgorithm imPriceAlgorithm = new ImPriceAlgorithm();
        imPriceAlgorithm.setCategoryType(new Byte(categoryType));
        imPriceAlgorithm.setSeasonCode(season);
        imPriceAlgorithm.setName(name);
        imPriceAlgorithm.setCreatedAt(new Date());
        imPriceAlgorithm.setUpdatedAt(new Date());
        imPriceAlgorithm.setEnabled(true);
        imPriceAlgorithmMapper.insert(imPriceAlgorithm);
        return imPriceAlgorithm.getImPriceAlgorithmId();
    }

    private void addAlgorithm(String season, String name, String categoryType) {
        String ruleType = "1";
        Long brandId = -1L;

        Long imPriceAlgorithmId = this.addImPriceAlgorithm(categoryType, season, name);
        Long imPriceAlgorithmRuleId = this.addImPriceAlgorithmRule(imPriceAlgorithmId, ruleType);
        this.addImPriceAlgorithmRuleBrand(brandId, imPriceAlgorithmRuleId);
        algorithmOperationMapper.initImPriceDiscountMapping(imPriceAlgorithmRuleId);
    }

    private void copyAlgorithm(Map<String, Object> data) throws Exception {
        Long categoryType = Long.valueOf(data.get("categoryType").toString());
        Map<String, Object> raw = (Map<String, Object>) data.get("raw");
        List<Map<String, Object>> targets = (List<Map<String, Object>>) data.get("targets");
        String rawSeason = raw.get("season").toString();

        // check
        List<Map<String, Object>> rawAlgorithms = algorithmOperationMapper.getAlgorithm(categoryType, rawSeason);
        for (Map<String, Object> target : targets) {

            List<Map<String, Object>> targetAlgorithms = algorithmOperationMapper.getPriceChangeRuleCountByCategoryAndSeason(categoryType,
                    target.get("targetSeason").toString());
            for (Map<String, Object> targetAlgorithm : targetAlgorithms) {
                boolean used = false;
                String targetName = StringUtils.trim(targetAlgorithm.get("name").toString());
                for (Map<String, Object> rawAlgorithm : rawAlgorithms) {
                    String rawName = StringUtils.trim(rawAlgorithm.get("name").toString());
                    if (targetName.equals(rawName)) {
                        used = true;
                        break;
                    }
                }
                if (!used) {
                    throw new ValidateException(new ErrorResponse(
                            AlgorithmValidationConstant.used_algorithm_desc + ",targetSeason:" + target.get("targetSeason").toString() + ",targetName:"
                                    + targetName));
                }
            }
        }

        for (Map<String, Object> target : targets) {
            String targetSeason = target.get("targetSeason").toString();
            algorithmOperationMapper.deleteImpriceAlgorithmRule(categoryType, targetSeason);

            for (Map<String, Object> algorithm : rawAlgorithms) {
                String name = algorithm.get("name").toString();

                Map<String, Object> idMap = new HashMap<>();
                Map<String, Object> idMap2 = new HashMap<>();
                Map<String, Object> idMap3 = new HashMap<>();

                List<Map<String, Object>> algorithmInfos = algorithmOperationMapper.getAlgorithmInfo(categoryType, rawSeason, name);
                for (Map<String, Object> algorithmInfo : algorithmInfos) {
                    Long algorithmRuleType = Long.parseLong(algorithmInfo.get("algorithmRuleType").toString());
                    Long brandId = Long.parseLong(algorithmInfo.get("brandId").toString());
                    int boutiqueDiscountOff = Integer.parseInt(algorithmInfo.get("boutiqueDiscountOff").toString());
                    int imDiscountOff = Integer.parseInt(algorithmInfo.get("imDiscountOff").toString());

                    /*String imPriceAlgorithmId = algorithmInfo.get("imPriceAlgorithmId").toString();
                    Long newImPriceAlgorithmId;
                    if (idMap.get(imPriceAlgorithmId) != null) {
                        newImPriceAlgorithmId = Long.parseLong(idMap.get(imPriceAlgorithmId).toString());
                    } else {
                        newImPriceAlgorithmId = this.addImPriceAlgorithm(categoryType.toString(), targetSeason, name);
                        idMap.put(imPriceAlgorithmId, newImPriceAlgorithmId);
                        algorithmOperationMapper.updatePriceChangeRuleImPriceAlgorithm(newImPriceAlgorithmId, Long.valueOf(imPriceAlgorithmId));
                    }*/

                    Long imPriceAlgorithmId = algorithmOperationMapper.getAlgorithmCountByCategoryAndSeasonAndName(categoryType, targetSeason, name);
                    Long newImPriceAlgorithmId;
                    if (imPriceAlgorithmId != null) {
                        newImPriceAlgorithmId = imPriceAlgorithmId;
                    } else {
                        newImPriceAlgorithmId = this.addImPriceAlgorithm(categoryType.toString(), targetSeason, name);
                    }

                    String imPriceAlgorithmRuleId = algorithmInfo.get("imPriceAlgorithmRuleId").toString();
                    Long newImPriceAlgorithmRuleId;
                    if (idMap.get(imPriceAlgorithmRuleId) != null) {
                        newImPriceAlgorithmRuleId = Long.parseLong(idMap.get(imPriceAlgorithmRuleId).toString());
                    } else {
                        newImPriceAlgorithmRuleId = this.addImPriceAlgorithmRule(newImPriceAlgorithmId, algorithmRuleType.toString());
                        idMap.put(imPriceAlgorithmRuleId, newImPriceAlgorithmRuleId);
                    }

                    String imPriceAlgorithmRuleBrandId = algorithmInfo.get("imPriceAlgorithmRuleBrandId").toString();
                    if (idMap2.get(imPriceAlgorithmRuleBrandId) == null) {
                        Long newImPriceAlgorithmRuleBrandId = this.addImPriceAlgorithmRuleBrand(brandId, newImPriceAlgorithmRuleId);
                        idMap2.put(imPriceAlgorithmRuleBrandId, newImPriceAlgorithmRuleBrandId);
                    }

                    if (idMap3.get(imPriceAlgorithmRuleId + "_" + boutiqueDiscountOff) == null) {
                        this.addImPriceDiscountMapping(newImPriceAlgorithmRuleId, 100 - boutiqueDiscountOff, 100 - imDiscountOff);
                        idMap3.put(imPriceAlgorithmRuleId + "_" + boutiqueDiscountOff, imDiscountOff);
                    }
                }
            }
        }
        algorithmOperationMapper.deleteImPriceAlgorithm();
        for (Map<String, Object> target : targets) {
            this.refreshSnapshotPrice(categoryType, target.get("targetSeason").toString());
        }
    }

    private void refreshSnapshotPrice(Long categoryType, String season) throws Exception {
        List<Map<String, Object>> algorithms = algorithmOperationMapper.getAlgorithm(categoryType, season);
        for (Map<String, Object> algorithm : algorithms) {
            Long imPriceAlgorithmId = Long.parseLong(algorithm.get("imPriceAlgorithmId").toString());
            logger.info("refreshSnapshotPrice,algorithm:{}", JsonTransformUtil.toJson(algorithm));
            iPriceRuleService.refreshSnapshotPrice(imPriceAlgorithmId);
        }
    }

}
